package com.star.spring.ratelimit.service;

import java.time.LocalDateTime;
import java.util.UUID;

import lombok.extern.slf4j.Slf4j;

import com.star.spring.ratelimit.model.AccessLog;
import com.star.spring.ratelimit.util.SystemInfoUtil;
import com.star.spring.ratelimit.util.UserAgentParser;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

/**
 * 访问日志服务
 *
 * @author star
 * @since 2025-01-24
 */
@Slf4j
@Service
public class AccessLogService {

    /**
     * 记录访问日志（异步）
     */
    @Async("logExecutor")
    public void logAccess(AccessLog accessLog) {
        try {
            // 补充系统信息
            enrichAccessLog(accessLog);

            // 记录详细日志
            logDetailedAccess(accessLog);

            // 记录简化日志
//            logSimpleAccess(accessLog);

        } catch (Exception e) {
            log.error("Failed to log access", e);
        }
    }

    /**
     * 补充访问日志信息
     */
    private void enrichAccessLog(AccessLog accessLog) {
        // 设置请求ID
        if (accessLog.getRequestId() == null) {
            accessLog.setRequestId(UUID.randomUUID().toString());
        }

        // 设置访问时间
        if (accessLog.getAccessTime() == null) {
            accessLog.setAccessTime(LocalDateTime.now());
        }

        // 设置服务器信息
        accessLog.setServerInfo(SystemInfoUtil.getServerInfo());

        // 设置内存使用情况
        accessLog.setMemoryUsed(SystemInfoUtil.getMemoryUsed());

        // 设置CPU使用情况
        accessLog.setCpuUsage(SystemInfoUtil.getCpuUsage());

        // 设置线程名称
        accessLog.setThreadName(Thread.currentThread().getName());

        // 解析用户代理信息
        if (accessLog.getUserAgent() != null) {
            UserAgentParser.UserAgentInfo userAgentInfo = UserAgentParser.parse(accessLog.getUserAgent());
            accessLog.setBrowser(userAgentInfo.getBrowser());
            accessLog.setOperatingSystem(userAgentInfo.getOperatingSystem());
            accessLog.setDevice(userAgentInfo.getDevice());
        }
    }

    /**
     * 记录详细访问日志
     */
    private void logDetailedAccess(AccessLog accessLog) {
        log.info("=== ACCESS LOG START ===");
        log.info("Request ID: {}", accessLog.getRequestId());
        log.info("Access Time: {}", accessLog.getAccessTime());
        log.info("Method: {}", accessLog.getMethod());
        log.info("URI: {}", accessLog.getUri());
        log.info("URL: {}", accessLog.getUrl());
        log.info("Client IP: {}", accessLog.getClientIp());
        log.info("Real IP: {}", accessLog.getRealIp());
        log.info("User Agent: {}", accessLog.getUserAgent());
        log.info("Browser: {}", accessLog.getBrowser());
        log.info("OS: {}", accessLog.getOperatingSystem());
        log.info("Device: {}", accessLog.getDevice());
        log.info("Session ID: {}", accessLog.getSessionId());
        log.info("User ID: {}", accessLog.getUserId());
        log.info("Request Params: {}", accessLog.getRequestParams());
        log.info("Request Body: {}", accessLog.getRequestBody());
        log.info("Response Status: {}", accessLog.getResponseStatus());
        log.info("Response Time: {}ms", accessLog.getResponseTime());
        log.info("Response data: {}", accessLog.getResponseData());
        log.info("Rate Limited: {}", accessLog.getRateLimited());
        log.info("Rate Limit Type: {}", accessLog.getRateLimitType());
        log.info("Rate Limit Key: {}", accessLog.getRateLimitKey());
        log.info("Server Info: {}", accessLog.getServerInfo());
        log.info("Thread Name: {}", accessLog.getThreadName());
        log.info("Memory Used: {}MB", accessLog.getMemoryUsed());
        log.info("CPU Usage: {}", accessLog.getCpuUsage());
        if (accessLog.getException() != null) {
            log.info("Exception: {}", accessLog.getException());
        }
        log.info("=== ACCESS LOG END ===");
    }

    /**
     * 记录简化访问日志
     */
    private void logSimpleAccess(AccessLog accessLog) {
        StringBuilder logMessage = new StringBuilder();
        logMessage.append("ACCESS: ");
        logMessage.append(accessLog.getMethod()).append(" ");
        logMessage.append(accessLog.getUri()).append(" ");
        logMessage.append("IP:").append(accessLog.getClientIp()).append(" ");
        logMessage.append("UA:").append(accessLog.getBrowser()).append(" ");
        logMessage.append("OS:").append(accessLog.getOperatingSystem()).append(" ");
        logMessage.append("Device:").append(accessLog.getDevice()).append(" ");
        logMessage.append("Status:").append(accessLog.getResponseStatus()).append(" ");
        logMessage.append("Time:").append(accessLog.getResponseTime()).append("ms ");

        if (accessLog.getRateLimited() != null && accessLog.getRateLimited()) {
            logMessage.append("RATE_LIMITED ");
        }

        if (accessLog.getException() != null) {
            logMessage.append("ERROR:").append(accessLog.getException());
        }

        log.info(logMessage.toString());
    }

    /**
     * 记录限流日志（异步）
     */
    @Async("logExecutor")
    public void logRateLimit(String key, String type, String message) {
        log.warn("RATE_LIMIT: key={}, type={}, message={}", key, type, message);
    }

    /**
     * 记录异常日志（异步）
     */
    @Async("logExecutor")
    public void logException(String requestId, String method, String uri, Exception e) {
        log.error("EXCEPTION: requestId={}, method={}, uri={}, error={}",
                requestId, method, uri, e.getMessage(), e);
    }
}
